粗解PageHelper分页逻辑

您所在的位置:网站首页 pagenum pagesize 粗解PageHelper分页逻辑

粗解PageHelper分页逻辑

2023-02-23 00:08| 来源: 网络整理| 查看: 265

起因

在学习若依管理系统的过程中,发现其系统的几乎没有分页的代码,很是疑惑。发现其使用了一个名为PageHelper的中间件,通过实现mybatis拦截器,拦截执行分页SQL,从而来实现后台分页功能,那么这个PageHelper的实现原理是什么样的?我们来粗略的探究一下。

参数获取与传递与保存

在学习的过程中,发现若依系统中出现分页时,在Controller层并没有编写如下获取分页参数的方法,例如:

@PreAuthorize("@ss.hasPermi('monitor:oper:list')") @GetMapping("/list") public TableDataInfo list(SysOper oper) { startPage(); // .... }

那么分页参数是如何获取的呢?又是如何传递给后续SQL的呢?

我们发现每次分页都与startPage()方法有关,猜测分页参数大概是在startPage()函数中获取的。看一下startPage源码:

/** * 设置请求分页数据 */ protected void startPage() { PageDomain pageDomain = TableSupport.buildPageRequest(); Integer pageNum = pageDomain.getPageNum(); Integer pageSize = pageDomain.getPageSize(); if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize)) { String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy()); Boolean reasonable = pageDomain.getReasonable(); PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable); } }

可以清楚地看到其中有两行:

Integer pageNum = pageDomain.getPageNum(); Integer pageSize = pageDomain.getPageSize();

查看其基础逻辑为通过TableSupport.buildPageRequest()构造一个PageDomain对象,其中通过:

getRequest().getParameter(name);

达到获取请求中的分页参数的目的。

那么后续分页参数是如何传递的呢?

作者使用了一个非常巧妙的对象:ThreadLocal。通过使用ThreadLocal保存分页的参数,以便后续使用。这个对象通常被称为线程局部变量。

我们来看一下逐层的逻辑,上述的startPage在最后一句调用:

PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);

其方法内部为:

/** * 基础分页方法 * * @author liuzh */ public abstract class PageMethod { /** * 开始分页 * * @param pageNum 页码 * @param pageSize 每页显示数量 * @param count 是否进行count查询 * @param reasonable 分页合理化,null时用默认配置 * @param pageSizeZero true且pageSize=0时返回全部结果,false时分页,null时用默认配置 */ public static Page startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) { Page page = new Page(pageNum, pageSize, count); page.setReasonable(reasonable); page.setPageSizeZero(pageSizeZero); //当已经执行过orderBy的时候 Page oldPage = getLocalPage(); if (oldPage != null && oldPage.isOrderByOnly()) { page.setOrderBy(oldPage.getOrderBy()); } setLocalPage(page); return page; } }

其中的关键是getLocalPage以及setLocalPage,我们来看一下这两个方法:

/** * 基础分页方法 * * @author liuzh */ public abstract class PageMethod { protected static final ThreadLocal LOCAL_PAGE = new ThreadLocal(); /** * 设置 Page 参数 * * @param page */ protected static void setLocalPage(Page page) { LOCAL_PAGE.set(page); } /** * 获取 Page 参数 * * @return */ public static Page getLocalPage() { return LOCAL_PAGE.get(); } }

在使用时,即可通过getLocalPage()方法获取到分页相关的参数。

总结

线程局部变量之前我只在阿里巴巴的日期格式化编码规范中见过,没想到线程局部变量的功能会如此强大与巧妙。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3